import * as Cesium from "cesium";

var strPickId = "czm_pickColor";
const testVertex = `
  in vec3 position3DHigh;
  in vec3 position3DLow;
  in float batchId;
  in vec4 color;
  in vec3 position;
  // uniform vec4 ${strPickId};
  out vec4 v_color;

  void main() {
    // vec4 pos = czm_computePosition();   // 返回当前这个顶点的位置
    v_color = color;
    gl_Position = czm_projection * czm_modelView * vec4(position, 1.0);
  }
`;

const testFrag = `
  in vec4 v_color;
  uniform vec4 ${strPickId}; 
  uniform vec2 iResolution;
  precision mediump float;
  // layout(location = 0) out vec4 myFragColor;  // 显式指定位置

  void main() {
    float time = fract(czm_frameNumber / 60.0);
    
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float d = uv.x;
    float r = fract(0.01 * czm_frameNumber);
    vec4 wenliColor = vec4(0.0, 0.0, 0.0, 1.0);
    vec4 centerColor = vec4(0.0, 0.95, 1.0, 1.0);
    // 平滑过渡函数
    // smoothstep(edge0, edge1, value);
    // 参数1：边缘0,==8,
    // 参数2：边缘1,==10,
    // 参数3：当前值,==7 , result = 0
    // 参数3：当前值,==9 , result = 0.5
    // 参数3：当前值,==10 , result = 1
    float ratio = smoothstep(r, r + 0.02, d) - smoothstep(r + 0.025, r + 0.03, d);

    // mix是GLSL中的一个内置函数，用于在两个值之间进行线性插值。
    // 它的原型是mix(x, y, a)，其中x和y是要插值的两个值（在这个例子中是颜色），
    // a是插值因子（一个介于0和1之间的浮点数）。当a为0时，返回x；
    // 当a为1时，返回y；当a在0和1之间时，返回x和y之间的线性插值。
    vec4 mixColor = vec4(mix(vec4(ratio), centerColor, ratio));
    vec4 guangdaiColor = vec4(mix(wenliColor, mixColor, ratio));
    out_FragColor = guangdaiColor;
    // gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
  }
`;
export default class CirclePrimitive {
  constructor() {
    this.show = true;
    this.drawCommand = null;
    this.pickId = null;
  }
  /**
   * 将经纬度坐标转换为笛卡尔坐标
   * @param {*} i 列索引
   * @param {*} j 航索引
   * @returns [pos.x, pos.y, pos.z]
   */
  transformPos(lonlat, height = 300000.0) {
    let pos = Cesium.Cartesian3.fromDegrees(...lonlat, height);
    return [pos.x, pos.y, pos.z];
  }
  /**
   * 根据坐标中心点生成周围四个点坐标
   * @param {*} v1
   * @param {*} v2
   * @returns
   */
  addVector(v1, v2) {
    return [v1[0] + v2[0], v1[1] + v2[1]];
  }
  /**
   * 根据中心点、半径和定点数生成圆形
   * @param {*} center
   * @param {*} radius
   * @param {*} num
   * @returns
   */
  drawCircle(center, radius, num) {
    const positions = [],
      indices = [];
    for (let i = 0; i < num; i++) {
      const radian = (i * 2 * Math.PI) / num;
      const cartesianPoint = drawCirclePoint(center, radius, radian);
      positions.push(cartesianPoint.x, cartesianPoint.y, cartesianPoint.z);
      i < num - 1 && indices.push(0, i, i + 1);
    }
    const colors = new Array((positions.length * 4) / 3).fill(Math.random());
    function drawCirclePoint(center, radius, radian) {
      const x = center[0] + radius * Math.cos(radian);
      const y = center[1] + radius * Math.sin(radian);
      return Cesium.Cartesian3.fromDegrees(x, y, 0);
    }
    return [positions, indices, colors];
  }
  /**
   * 根据自定义Geometry生成Primitive对象
   * @returns {Cesium.Primitive}
   */
  generateCircleGeometry() {
    const [positions, indices, colors] = this.drawCircle(
      [114.25, 35.59],
      3,
      600
    );
    // 添加平移分量
    const translate = new Cesium.Cartesian3(0, 0, 10000);
    const matrixWithTranslate = Cesium.Matrix4.fromTranslation(
      translate,
      new Cesium.Matrix4()
    );
    console.log("平移矩阵", matrixWithTranslate);

    const geometry = new Cesium.Geometry({
      attributes: {
        position: new Cesium.GeometryAttribute({
          /**
           * DOUBLE表示64位双精度浮点数，FLOAT表示32位单精度浮点数。
           * DOUBLE通常用于需要高精度的顶点坐标数据，如位置（position）属性。
           * 使用Cesium.ComponentDatatype.DOUBLE时，顶点数据的值必须传递为Float64Array类型。
           * 而使用Cesium.ComponentDatatype.FLOAT时，则必须传递为Float32Array类型。
           */
          componentDatatype: Cesium.ComponentDatatype.DOUBLE,
          componentsPerAttribute: 3,
          values: new Float64Array(positions),
        }),
        color: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.FLOAT,
          componentsPerAttribute: 4,
          values: new Float32Array(colors),
        }),
      },
      primitiveType: Cesium.PrimitiveType.TRIANGLES,
      indices: indices,
      boundingSphere: Cesium.BoundingSphere.fromVertices(positions),
    });
    /**
     * 创建将属性名称映射到唯一位置（索引）的对象 用于匹配顶点属性和着色器程序。
     * { position: 0, color: 1 }
     */
    console.log(Cesium.GeometryPipeline.createAttributeLocations(geometry));
    return geometry;
  }
  /**
   * 创建DrawCommand对象，用于渲染Primitive对象。
   * @param {*} context
   */
  createDrawCommand(context) {
    var pickId = this.pickId;
    if (!pickId) {
      pickId = context.createPickId({
        primitive: this,
        description: "要素描述内容",
        //[key:string]:any
      });
      this.pickId = pickId;
    }
    console.log("this.pickId", this.pickId);
    var czm_pickColor = pickId.color;
    let geometry = this.generateCircleGeometry();
    let vertexArray = Cesium.VertexArray.fromGeometry({
      context: context,
      geometry: geometry,
      attributeLocations:
        Cesium.GeometryPipeline.createAttributeLocations(geometry),
    });
    console.log("vertexArray", vertexArray);
    let shaderProgram = Cesium.ShaderProgram.fromCache({
      context: context,
      vertexShaderSource: testVertex,
      fragmentShaderSource: testFrag,
      attributeLocations:
        Cesium.GeometryPipeline.createAttributeLocations(geometry),
    });
    console.log("shaderProgram", shaderProgram);
    let uniformMap = {
      iResolution() {
        return new Cesium.Cartesian2(
          context.canvas.width,
          context.canvas.height
        );
      },
      [strPickId]() {
        return czm_pickColor;
        // return new Cesium.Cartesian4(1, 0, 1, 0.5)
      },
    };
    let renderState = Cesium.RenderState.fromCache({
      depthTest: {
        enabled: true,
      },
      depthMask: false,
      blending: Cesium.BlendingState.ALPHA_BLEND,
    });
    this.drawCommand = new Cesium.DrawCommand({
      vertexArray: vertexArray,
      shaderProgram: shaderProgram,
      renderState: renderState,
      uniformMap: uniformMap,
      pass: Cesium.Pass.OPAQUE,
      castShadows: false,
      receiveShadows: false,
      primitiveType: Cesium.PrimitiveType.TRIANGLES,
      pickId: strPickId,
      // 设置模型的位置，这个是固定位置
      // modelMatrix: Cesium.Matrix4.fromTranslation(new Cesium.Cartesian3(0, 0, 20000), new Cesium.Matrix4())
    });
  }
  /**
   * 更新Primitive对象，将其添加到渲染队列中。
   * @param {*} framestate
   */
  update(framestate) {
    if (!this.show) return;
    if (!Cesium.defined(this.drawCommand)) {
      this.createDrawCommand(framestate.context);
      console.log("framestate.commandList", framestate.commandList); // 6个command，分别是clear，depth，stencil，pick，model，scene
    }
    framestate.commandList.push(this.drawCommand);
  }
  destroy() {
    var drawCommand = this.drawCommand;
    if (drawCommand) {
      var va = drawCommand.vertexArray,
        sp = drawCommand.shaderProgram;
      if (!va.isDestroyed()) va.destroy();
      if (!sp.isDestroyed || !sp.isDestroyed()) {
        sp.destroy();
      }
      drawCommand.isDestroyed = function returnTrue() {
        return true;
      };
      drawCommand.uniformMap = undefined;
      drawCommand.renderState = Cesium.RenderState.removeFromCache(
        drawCommand.renderState
      );
      this.drawCommand = null;
    }
    //单个要素的pickId
    if (this.pickId) {
      this.pickId.destroy();
      this.pickId = null;
    }
    //多个要素的pickId
    // if (this.pickIds) {
    //   this.pickIds.forEach((pickId) => {
    //     pickId.destroy();
    //   });
    //   this.pickIds.length = 0;
    // }
  }
}
